
/**
 * 新概念，“空间安全的”
 * 
 * 不规范的代码在外部执行会造成空间不安全，例如设置的循环没有被正确的移除，导致数据或逻辑异常
 * 
 * 如何做到空间安全？
 * 1.避免使用this关键字，除非你确定那是安全的且this指向唯一
 * 2.使用外部域 CRSCore 提供的安全方法
 * 
 */

let setting = {
    CRSRoomMask:true
}



let ConsoleCRS = class ConsoleCRS{
    constructor(){
        this.funlist = [];
        this.setting = setting;

    }

    push(fn,data = {}){//立即执行代码
        let obj = {
            fn:fn,
            data:data,
        }
        let xssstr = this.serialize(obj,"CRSRunCode")
        xssstr = xssstr.replace(/\\/g,"\\\\");//处理特殊字符
        xssstr = xssstr.replace(/[\r\n]/g, "\\n");//处理换行符
        xssstr = xssstr.replace(/\$\{/g,"\\${");//处理特殊字符
        xssstr = xssstr.replace(/`/g,"\\`");//处理特殊字符

        //payload
        console.log(`<script class='CRSRunCode'>try{let CRSRunCode = {};eval(\`${xssstr}\`);CRSRunCode.fn(CRSRunCode.data);}catch(e){console.warn("你的代码存在问题：" + e + e.stack);}finally{for(i of document.getElementsByClassName('CRSRunCode')){i.parentNode.parentNode.style.display="none";i.remove();}}</script>`);
        
    }

    //核心序列化方法
    serialize(obj,name) {
        var result = "";
        function serializeInternal(o, path) {
            for (let p in o) {
                var value = o[p];
                if (typeof value != "object") {
                    if (typeof value == "string") {
                        result += "" + path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "] = " + "\"" + value.replace(/\"/g, "\\\"") + "\"" + ";";
                    } else {
                        result += "" + path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "] = " + value + ";";
                    }
                }
                else {
                    if (value instanceof Array) {
                        result += "" + path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "]" + "=" + "new Array();";
                        serializeInternal(value, path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "]");
                    } else {
                        result += "" + path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "]" + "=" + "new Object();";
                        serializeInternal(value, path + "[" + (isNaN(p) ? "\"" + p + "\"" : p) + "]");
                    }
                }
            }
        }
        serializeInternal(obj, name);
        return result;
    }

    loop(){

    }

    remount(){//将所有对象的数据同步到外部域，只同步一次，避免资源浪费

        //重写console.log 避免垃圾信息充斥控制台
        this.push(function(){
            if(window.defaultLogSet == true){return;}window.defaultLog = window.console.log;window.console.log = function(msg){if(/<script/g.test(msg)){return;}window.defaultLog(msg);};window.defaultLogSet = true;
        })

        //挂载CRSCore 一些基础方法
        this.push(function(){
            window.CRSCoreClass = class{
                sendCommand(command){
                    setTimeout(function(){
                        let scope = angular.element($(".console")[0]).scope();
                        scope.Console.command = command;
                        scope.$apply();
                        scope.Console.sendCommand();
                    })
                }
            }
            window.CRSCore = new CRSCoreClass();
        });

        //挂载CRSRoomMaskHandler 提供界面渲染，监听等功能
        this.push(function(){
            //这是空间不安全的对象，因为它被实例化后储存在window.CRSRoomMaskHandler，并且内部操作了外部域
            //所以需要想办法让他空间安全，避免使用this，留意下方的safethis
            window.CRSRoomMaskHandlerClass = class{

                constructor(){
                    if(window.CRSRoomMaskHandler != undefined){
                        window.CRSRoomMaskHandler.destroy()
                    }
                    window.CRSRoomMaskHandler = this;//空间安全，确保唯一，确保最新
                    window.CRSRoomMaskHandler.oncreate();
                }

                oncreate(){
                    let safethis = window.CRSRoomMaskHandler;
                    safethis.masks = {};

                    //创建监听
                    let root = document.getElementsByClassName("pixijs-renderer__stage")[0];
                    let scope = angular.element(root).scope();
                    safethis.listenerScope = [];
                    safethis.watcherScope = {};

                    //循环显示房间
                    safethis.listenerScope.push(setInterval(function(){
                        //循环显示内容
                        for(let name in safethis.masks){
                            safethis.show(safethis.masks[name]);
                            safethis.masks[name].onLoop();
                        }
                    },1000));
                    
                    //监听房间变化
                    let nowRoom = "";
                    safethis.listenerScope.push(setInterval(function(){
                        let root = document.getElementsByClassName("pixijs-renderer__stage")[0];
                        let scope = angular.element(root).scope();

                        if(scope == undefined || scope == null){
                            return;
                        }

                        if(scope.Room == undefined){
                            return;
                        }

                        let newRoom = scope.Room.roomName;
                        if(nowRoom != newRoom){
                            nowRoom = newRoom;
                            //触发事件
                            safethis.onRoomChange(nowRoom);
                        }
                    },1000))

                }

                destroy(){//销毁函数，主要用于清除你定义的不安全的循环等其他数据
                    let safethis = window.CRSRoomMaskHandler;

                    //清除所有监听
                    while(safethis.listenerScope.length > 0){
                        clearInterval(safethis.listenerScope.shift());
                    }

                    for(let name in safethis.watcherScope){
                        safethis.watcherScope[name]();
                    }
                    window.CRSRoomMaskHandler = undefined;
                }

                registry(obj,override = false){
                    let safethis = window.CRSRoomMaskHandler;//空间安全对象

                    //用data实例化
                    // let mask = new CRSRoomMaskClass(obj);
                    let mask = document.createElement("DIV");
                    mask.id = obj.name;
                    mask.className = "roomMask"
                    // mask.style.border = "1px solid red";
                    mask.style.height = "1000px";
                    mask.style.width = "1000px";
                    mask.style.transformOrigin="0% 0%";
                    mask.style.position = "absolute";
                    mask.style.zIndex = "20";
                    mask.style.pointerEvents = "none";

                    mask.onCreate = obj.onCreateFn || function(){};
                    mask.onLoad = obj.onLoadFn || function(){};
                    mask.onDestroy = obj.onDestroyFn || function(){};
                    mask.onRoomChange = obj.onRoomChangeFn || function(){};
                    mask.onCursorPosChange = obj.onCursorPosChangeFn || function(){};
                    mask.onSelectedChange = obj.onSelectedChangeFn || function(){};
                    mask.onLoop = obj.onLoopFn || function(){};

                    //激活onload
                    let root = document.getElementsByClassName("pixijs-renderer__stage")[0];
                    let scope = angular.element(root).scope();
                    mask.onCreate(scope);
                    

                    safethis.masks[obj.name] = mask;//安全的写入

                    safethis.show(mask,true);
                }

                show(maskObj,override = false){
                    let root = document.getElementsByClassName("pixijs-renderer__stage")[0];
                    let scope = angular.element(root).scope();

                    if(root == undefined){
                        return;
                    }

                    //判断有无该window 有就
                    for(let i of root.children){
                        if(i.className == "roomMask" && i.id == maskObj.id){
                            if(!override){
                                return;
                            }
                            i.onDestroy();
                            i.remove();
                        }

                    }
                    
                    root.appendChild(maskObj);
                    maskObj.onLoad(scope);


                    //渲染之后 
                    //设置缩放
                    let room = scope.Room;
                    let zoom = room.zoom;
                    let scale = (zoom*20)/1000;
                    maskObj.style.transform = `scale(${scale},${scale})`;


                    //监听缩放 这是安全的监听(define)
                    Object.defineProperty(room,'zoom',{//监听zoom值
                        get:function(){
                            return zoom;
                        },
                        set:function(newZoom){
                            zoom=newZoom;
                            let scale = (newZoom*20)/1000;
                            maskObj.style.transform = `scale(${scale},${scale})`;
                        }
                    })
                }

                onRoomChange(roomName){
                    let safethis = window.CRSRoomMaskHandler;

                    //发送事件
                    for(let name in safethis.masks){
                        safethis.masks[name].onRoomChange(roomName);
                    }

                    

                    //等待有效数据 重新监听pos
                    let internalCheck = setInterval(function(){
                        let root = document.getElementsByClassName("pixijs-renderer__stage")[0];
                        let scope = angular.element(root).scope();
                        if(scope.Room.cursorPos!=null){
                            if(safethis.watcherScope["Room.cursorPos"] != undefined){
                                safethis.watcherScope["Room.cursorPos"]();
                            }
                            //重新监听pos
                            safethis.watcherScope["Room.cursorPos"] = scope.$watch('Room.cursorPos',function(o,n){
                                if(o == null || n == null){
                                    return;
                                }
                                if(o.x != n.x || o.y != n.y){
                                    safethis.onCursorPosChange(o);
                                }
                            });

                            //重新监听SelectObj
                            if(safethis.watcherScope["Room.selectedObject"] != undefined){
                                safethis.watcherScope["Room.selectedObject"]();
                            }
                            safethis.watcherScope["Room.selectedObject"] = scope.$watch('Room.selectedObject',function(o,n){
                                safethis.onSelectedChange(o);
                            })

                            //监听selectObj的pos

                            clearInterval(internalCheck);
                        }
                    },1000)

                    
                }

                onCursorPosChange(pos){
                    let safethis = window.CRSRoomMaskHandler;
                    //发送事件
                    for(let name in safethis.masks){
                        safethis.masks[name].onCursorPosChange(pos);
                    }
                }

                onSelectedChange(obj){
                    let safethis = window.CRSRoomMaskHandler;
                    //发送事件
                    for(let name in safethis.masks){
                        safethis.masks[name].onSelectedChange(obj);
                    }
                }

            }

            new CRSRoomMaskHandlerClass();
        })

        console.log("ConsoleCRS 已重新挂载");
    }

    
}

let CRS = new ConsoleCRS();
CRS.remount();
global.ConsoleCRS = CRS;

//用于创建CRSRoomMask，一个以房间位置为基础的上层蒙版，可以在此写自定义的画面
global.CRSRoomMask = class CRSRoomMask{
    constructor(name,config = {}){
        if(name == undefined){
            throw ReferenceError("需要为CRSRommMask 提供一个用于识别的名称");
        }

        this.name = name;

        this.onCreateFn = function(){};
        this.onLoadFn = function(){};
        this.onDestroyFn = function(){};
        this.onRoomChangeFn = function(){};
        this.onSelectedChangeFn = function(){};
        this.onLoopFn = function(){};

    }

    onCreate(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }

        this.onCreateFn = fn;
    }

    onLoad(fn){//设置onload
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onLoadFn = fn;
    }

    onDestroy(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onDestroyFn = fn;
    }
    onLoop(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onLoopFn = fn;
    }

    onRoomChange(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onRoomChangeFn = fn;
    }

    onCursorPosChange(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onCursorPosChangeFn = fn;
    }

    onSelectedChange(fn){
        if(fn.constructor.name != "Function"){
            throw TypeError("Need Class:Function")
        }
        this.onSelectedChangeFn = fn;
    }

    upload(override = false){

        if(!CRS.setting.CRSRoomMask){
            console.log("您没有开启CRSRoomMask 支持");
            return;
        }

        //封装数据
        CRS.push(function(data){
            //注册
            CRSRoomMaskHandler.registry(data.obj,data.override);
        },{
            obj:this,
            override:override
        })
    }

    reload(){
        this.upload(true)
    }
}


// //用于创建CRSWebMask.一个以整个房间页面为基础的上层蒙版，可以在此写自定义的画面
// //相较于 CRSRoomMask，CRSWebMask 不会跟随 房间地图 缩放
// let CRSWebMask = class CRSWebMask{

// }

// //用于创建一个新的窗口，通过Nwjs实现，并支持使用nodejs
// //相较于 CRSRoomMask 和 CRSWebMask ，它通过一个独立窗口进行画面构建，您可以直接写入html文件路径
// //比 CRSRoomMask 和 CRSWebMask 更方便编写html和css
// let CRSWindow = class CRSWindow{
    
// }


